/***************************************************
> Copyright (C) 2024 ==KINGYI== All rights reserved.
> File Name: server.c
> Author: KAIJIE.JIANG
> Mail: 
> Created Time: 2024年08月16日 星期五 17时13分59秒
***************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cJSON.h>

struct calculate{
	char type[10];
	int data1;
	int data2;
};

struct result{
	char type[20];
	float res;
};

void fun(int listenfd,char *buf);
void setpack(char *buf,struct result *res);
void unpack(char *buf,struct result *res);

int main()
{
    //create
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    
	//bind
    struct sockaddr_in myaddr;
    myaddr.sin_family = AF_INET;
    myaddr.sin_port = htons(6868);
    //myaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //INADDR_ANY 自动提取本机ip地址
    myaddr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY 自动提取本机ip地址

    int ret = bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr));
    printf("bind ret = %d\n", ret);
	if(ret == -1){
		perror("bind");
		exit(-1);
	}
    
	//listen
    listen(fd, 5);
	printf("fd = %d\n",fd);
    
	//init
    fd_set rd_fds, rd_fds_bk;
    FD_ZERO(&rd_fds);
    FD_SET(fd, &rd_fds);//将服务器的fd设置进去
    int maxfd = fd + 1;//设置maxfd
    
	//back up rd_fds
    rd_fds_bk = rd_fds;
    
	//
    while(1)
    {
 
        int ret = select(maxfd, &rd_fds, NULL, NULL, 0);
        if (ret < 0)
        {
            perror("Error:select");
            break;
        }
 
            int i;
            for (i = 0; i < maxfd; i++)
            {
                if (FD_ISSET(i, &rd_fds))
                {
                    if (i == fd)//是server的fd的时候，意味着是产生了新的连接
                    {
                        //accept
                        int new_fd = accept(fd, NULL, NULL);
                        FD_SET(new_fd, &rd_fds_bk);
                        maxfd = maxfd > new_fd + 1 ? maxfd : new_fd + 1;
                        printf("newfd:%d\n", new_fd);
						printf("maxfd:%d\n",maxfd);
                    }
                    else
                    {
						char buf[1024] = {0};
                        //recv
                        int len = recv(i, buf, 1024, 0);
                        if (len <= 0)
                        {
                            //意味着连接已经断开
                            //close
                            FD_CLR(i, &rd_fds_bk);//将其从全局中去掉
                            close(i);
                            printf("close fd:%d\n", i);
                        }
                        else
                        {
							fun(i,buf);
                        }
                    }
                }
            }
        }
        rd_fds = rd_fds_bk;//保证下次调用select的时候，rd_fds里面有所有的fd
    }
    close(fd);
    return 0;
}

void fun(int listenfd,char *buf){
	int ret = 0;
	struct result res;
	memset(&res,0,sizeof(struct result));

	unpack(buf,&res);

//	printf("ret = %d\n",ret);

	memset(buf,0,sizeof(char)*1024);

	setpack(buf,&res);

	ret = send(listenfd,buf,strlen(buf),0);
	if(ret == -1)
	{
		perror("send");
		exit(-1);
	}
}

void setpack(char *buf,struct result *res){
	cJSON *json = NULL;
	json = cJSON_CreateObject();

	cJSON_AddItemToObject(json,"type",cJSON_CreateString(res->type));
	cJSON_AddItemToObject(json,"res",cJSON_CreateNumber(res->res));

	char *dest = cJSON_Print(json);
	strcpy(buf,dest);

	free(dest);
	cJSON_Delete(json);
}

void unpack(char *buf,struct result *res){
	cJSON * json = NULL;
	struct calculate cal;

	memset(&cal,0,sizeof(struct calculate));
	json = cJSON_Parse(buf);

	cJSON *node = NULL;
	node = cJSON_GetObjectItem(json,"type");
	if(node == NULL){
		printf("error:cJSON_GetObjectItem\n");
		cJSON_Delete(json);
		exit(-1);
	}
	if(node->type == cJSON_String){
		printf("type:%s\n",node->valuestring);
		strcpy(cal.type,node->valuestring);
	}

	node = cJSON_GetObjectItem(json,"data1");
	if(node == NULL){
		printf("error:cJSON_GetObjectItem\n");
		cJSON_Delete(json);
		exit(-1);
	}
	if(node->type == cJSON_Number){
		printf("data1:%d\n",node->valueint);
		cal.data1 = node->valueint;
	}
	
	node = cJSON_GetObjectItem(json,"data2");
	if(node == NULL){
		printf("error:cJSON_GetObjectItem\n");
		cJSON_Delete(json);
		exit(-1);
	}
	if(node->type == cJSON_Number){
		printf("data2:%d\n",node->valueint);
		cal.data2 = node->valueint;
	}

	cJSON_Delete(json);
	node = NULL;

	if(strcmp(cal.type,"add") == 0){
		strcpy(res->type,"res");
		res->res = cal.data1 + cal.data2;
	}else if(strcmp(cal.type,"sub") == 0){
		strcpy(res->type,"res");
		res->res = cal.data1 - cal.data2;
	}else if(strcmp(cal.type,"mul") == 0){
		strcpy(res->type,"res");
		res->res = cal.data1 * cal.data2;
	}else if(strcmp(cal.type,"div") == 0){
		if(cal.data2 == 0){
			strcpy(res->type,"error:data2");
		}else{
			strcpy(res->type,"res");
			res->res = (double)cal.data1 / cal.data2;
		}
	}else if(strcmp(cal.type,"quit") == 0){
		strcpy(res->type,"quit");
	}else{
		strcpy(res->type,"error:type");
	}
}
